package com.annotation;  
  
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.jsb.common.utils.IdGen;
import com.jsb.common.utils.NetworkUtil;
import com.jsb.model.Admin;
import com.jsb.model.SysLog;
import com.jsb.service.SysLogService;
import com.jsb.shiro.UserUtils;
  
/** 
 * 切点类 
 * @author tiangai 
 * @since 2014-08-05 Pm 20:35 
 * @version 1.0 
 */  
@Aspect  
@Component  
public class SystemLogAspect {  
    //注入Service用于把日志保存数据库  
    @Resource  
    private SysLogService logService;  
    //本地异常日志记录对象  
    private static final Logger logger = LoggerFactory.getLogger(SystemLogAspect.class);  
  
    //Service层切点  
    @Pointcut("@annotation(com.annotation.SystemServiceLog)")  
    public void serviceAspect() {  
    }  
  
    //Controller层切点  
    @Pointcut("@annotation(com.annotation.SystemControllerLog)")  
    public void controllerAspect() {  
    }  
  
    /** 
     * 前置通知 用于拦截Controller层记录用户的操作 
     * 
     * @param joinPoint 切点 
     */  
    @After("controllerAspect()")  
    public void doBefore(JoinPoint joinPoint) {  
  
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();  
        HttpSession session = request.getSession();  
        //读取session中的用户  
        Subject subject = SecurityUtils.getSubject();
        String principal = (String) subject.getPrincipal();
//        Admin user = (Admin) session.getAttribute("loginUser");  
        //请求的IP  
        String ip = NetworkUtil.getIpAddr(request);  
      //获取用户请求方法的参数并序列化为JSON格式字符串  
        String params = "";  
        if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {  
        	params = optionContent(joinPoint.getArgs(),joinPoint.getSignature().getName());
        }  
        try {  
            SysLog log = new SysLog();
            log.setId(IdGen.uuid());
            log.setCreateBy(principal);
            log.setCreateDate(new Date());
            log.setIp(ip);
            log.setMethod(joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()");
            log.setRequestUri(request.getRequestURI());
            log.setTitle(getControllerMethodDescription(joinPoint));
            log.setParams(params);
            log.setType("0");  
            
            //保存数据库  
            logService.addSysLog(log);
        } catch (Exception e) {  
            //记录本地异常日志  
            logger.error("==前置通知异常==");  
            logger.error("异常信息:{}", e.getMessage());  
        }  
    }  
  
    /** 
     * 异常通知 用于拦截service层记录异常日志 
     * 
     * @param joinPoint 
     * @param e 
     */  
    @AfterThrowing(pointcut = "serviceAspect()", throwing = "e")  
    public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {  
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();  
        HttpSession session = request.getSession();  
        //读取session中的用户  
        Admin user = (Admin) session.getAttribute("loginUser");  
        //获取请求ip  
        String ip = NetworkUtil.getIpAddr(request);  
        //获取用户请求方法的参数并序列化为JSON格式字符串  
        String params = "";  
        if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {  
        	params = optionContent(joinPoint.getArgs(),joinPoint.getSignature().getName());
        }  
        try {  
            SysLog log = new SysLog();
            log.setCreateBy(user.getAccount());
            log.setCreateDate(new Date());
            log.setException("异常代码:" + e.getClass().getName()+"异常信息:" + e.getMessage());
            log.setTitle(getServiceMthodDescription(joinPoint));
            log.setMethod(joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()");
            log.setParams(params);
            log.setRequestUri(request.getRequestURI());
            log.setIp(ip);
            log.setType("1");
            //保存数据库  
            logService.addSysLog(log);  
//            System.out.println("=====异常通知结束=====");  
        } catch (Exception ex) {  
            //记录本地异常日志  
            logger.error("==异常通知异常==");  
            logger.error("异常信息:{}", ex.getMessage());  
        }  
         /*==========记录本地异常日志==========*/  
        logger.error("异常方法:{}异常代码:{}异常信息:{}参数:{}", joinPoint.getTarget().getClass().getName() + joinPoint.getSignature().getName(), e.getClass().getName(), e.getMessage(), params);  
  
    }  
  
  
    /** 
     * 获取注解中对方法的描述信息 用于service层注解 
     * 
     * @param joinPoint 切点 
     * @return 方法描述 
     * @throws Exception 
     */  
    public static String getServiceMthodDescription(JoinPoint joinPoint)  
            throws Exception {  
        String targetName = joinPoint.getTarget().getClass().getName();  
        String methodName = joinPoint.getSignature().getName();  
        Object[] arguments = joinPoint.getArgs();  
        Class targetClass = Class.forName(targetName);  
        Method[] methods = targetClass.getMethods();  
        String description = "";  
        for (Method method : methods) {  
            if (method.getName().equals(methodName)) {  
                Class[] clazzs = method.getParameterTypes();  
                if (clazzs.length == arguments.length) {  
                    description = method.getAnnotation(SystemServiceLog.class).description();  
                    break;  
                }  
            }  
        }  
        return description;  
    }  
  
    /** 
     * 获取注解中对方法的描述信息 用于Controller层注解 
     * 
     * @param joinPoint 切点 
     * @return 方法描述 
     * @throws Exception 
     */  
    public static String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {  
        String targetName = joinPoint.getTarget().getClass().getName();  
        String methodName = joinPoint.getSignature().getName();  
        Object[] arguments = joinPoint.getArgs();  
        Class targetClass = Class.forName(targetName);  
        Method[] methods = targetClass.getMethods();  
        String description = "";  
        for (Method method : methods) {  
            if (method.getName().equals(methodName)) {  
                Class[] clazzs = method.getParameterTypes();  
                if (clazzs.length == arguments.length) {  
                    description = method.getAnnotation(SystemControllerLog.class).description();  
                    break;  
                }  
            }  
        }  
        return description;  
    } 
    
    /** 
     * 使用Java反射来获取被拦截方法的参数值，  
     * 将参数值拼接为操作内容 
     * @param args 参数值 
     * @param mName 方法名 
     * @return 
     */  
    public String optionContent(Object[] args, String mName){  
        if(args == null){  
            return null;  
        }  
        StringBuffer rs = new StringBuffer();  
        rs.append(mName);  
        String className = null;  
        int index = 1;  
        //遍历参数对象   
        for(Object info : args){  
            //获取对象类型  
        	if(info==null){
        		continue;
        	}
            className = info.getClass().getName();  
            className = className.substring(className.lastIndexOf(".") + 1);  
            rs.append("[参数"+index+"，类型:" + className + "，值:");  
            //如果是基本数据类型,List,Map则直接获取值  
            if(info instanceof String  
                    || info instanceof Integer  
                    || info instanceof Double  
                    || info instanceof Float  
                    || info instanceof BigDecimal  
                    || info instanceof List  
                    || info instanceof Map){  
                rs.append(info);  
            }else {  
                //如果是domain对象则获取对象所有特性的get()方法，或者规范domain重写toString()，统一用toString();  
                Method[] methods = info.getClass().getDeclaredMethods();  
                // 遍历方法，判断get方法   
                for(Method method : methods){  
                    String methodName = method.getName();  
                    if(methodName.indexOf("get") == -1){//不是get方法   
                        continue;  
                    }  
                    Object rsValue = null;  
                    try{  
                          
                        rsValue = method.invoke(info);  
                    }catch (Exception e) {  
                        continue;  
                    }  
                    rs.append("(" + methodName+ ":" + rsValue + ")");  
                }  
            }  
            rs.append("]");  
            index ++;  
        }  
        return rs.toString();  
    }  
}  